package cn.yotta.user.web.autoconfiguration.config;


import cn.yotta.user.api.user.UserReadApi;
import cn.yotta.user.web.autoconfiguration.filter.HeaderContextFilter;
import cn.yotta.user.web.autoconfiguration.filter.UserContextFilter;
import cn.yotta.user.web.autoconfiguration.properties.LoginCookieNameProperties;
import cn.yotta.user.web.autoconfiguration.properties.WhitePathsProperties;
import cn.yotta.user.web.autoconfiguration.provider.LoginUserLoadProvider;
import cn.yotta.user.web.autoconfiguration.provider.UserReadFromTokenProvider;
import cn.yotta.user.web.autoconfiguration.provider.impl.DefaultLoginUserLoadProvider;
import cn.yotta.user.web.autoconfiguration.provider.impl.YottaRemoteUserReadFeignProvider;
import cn.yotta.user.web.autoconfiguration.token.CookieLoginTokenObtainStrategy;
import cn.yotta.user.web.autoconfiguration.token.LoginTokenObtainStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;

/**
 * @author wyaoyao
 * @date 2022/11/8 17:07
 */
@Slf4j
@Configuration
@EnableConfigurationProperties({WhitePathsProperties.class, LoginCookieNameProperties.class})
public class UserWebContextConfiguration {

    /**
     * 适配user-core远程调用的实现
     * 当前类路径下有UserReadApi这个类，
     * UserReadFromTokenProviderAutoConfiguration这个配置才会生效
     */
    @ConditionalOnClass(UserReadApi.class)
    @Configuration
    static class UserReadFromTokenProviderAdaptorCoreAutoConfiguration {


        /**
         * 不仅仅需要类路径下有UserReadApi这个class
         * 还需要容器中有UserReadApi的bean
         */
        @Bean
        @ConditionalOnBean(UserReadApi.class)
        @ConditionalOnMissingBean(UserReadFromTokenProvider.class)
        public UserReadFromTokenProvider userReadFromTokenProvider(UserReadApi userReadApi) {
            return new YottaRemoteUserReadFeignProvider(userReadApi);
        }

    }

    @Bean
    public FilterRegistrationBean<Filter> registrationLoginFilterBean(WhitePathsProperties whitePathsProperties, LoginUserLoadProvider loginUserLoadProvider
    ) {

        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new UserContextFilter(whitePathsProperties, loginUserLoadProvider));
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(UserContextFilter.ORDER);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean<Filter> registrationHeaderContextFilterBean() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new HeaderContextFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(HeaderContextFilter.ORDER);
        return registrationBean;
    }

    @Bean
    @ConditionalOnMissingBean(LoginTokenObtainStrategy.class)
    public LoginTokenObtainStrategy loginTokenObtainStrategy(LoginCookieNameProperties properties) {
        return new CookieLoginTokenObtainStrategy(properties.getCookieName());
    }


    @Bean
    @ConditionalOnMissingBean(LoginUserLoadProvider.class)
    public LoginUserLoadProvider loginUserLoadProvider(LoginTokenObtainStrategy loginTokenObtainStrategy,
                                                      @Autowired(required = false) UserReadFromTokenProvider userReadFromTokenProvider){
        if (userReadFromTokenProvider == null) {
            log.error("container not find this UserReadFromTokenProvider bean; you should implement this and put into container");
            throw new NoSuchBeanDefinitionException("userReadFromTokenProvider");
        }
        return new DefaultLoginUserLoadProvider(loginTokenObtainStrategy, userReadFromTokenProvider);
    }
}
